﻿using Epic.Net.Utility;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Epic.Net.Extensions;

namespace Epic.Net
{
    public class LittleEndianBufferWriter 
    {

        public LittleEndianBufferWriter(Stream stream)

        {
        }


        public LittleEndianBufferWriter(Stream stream, Encoding encoding)

        {
        }





    }

    public class BigEndianBufferWriter : BufferWriter
    {

        internal BigEndianBufferWriter()
            : base()
        {
        }

        internal BigEndianBufferWriter(Encoding encoding)
            : base(encoding)
        {
        }

        internal BigEndianBufferWriter(Stream stream)
            : base(stream)
        {
        }


        internal BigEndianBufferWriter(Stream stream, Encoding encoding)
            : base(stream, encoding)
        {
        }

        byte[] WriteInner(params byte[] value)
        {
            base.BaseStream.Write(value, 0, value.Length);
            return value;
        }



        public override void Write(byte value, Action<byte[]> before = null, Action<byte[]> after = null)
        {
            this.Write(new byte[] { value }, before, after);
        }

        public override void Write(byte[] value, Action<byte[]> before = null, Action<byte[]> after = null)
        {
            this.WriteInner(value.Action(before)).Action(after);
        }

        public override void Write(short value, Action<byte[]> before = null, Action<byte[]> after = null)
        {
            this.WriteInner(BufferUtility.ToBytes(value).Action(before)).Action(after);
        }

        public override void Write(int value, Action<byte[]> before = null, Action<byte[]> after = null)
        {
            this.WriteInner(BufferUtility.ToBytes(value).Action(before)).Action(after);
        }

        public override void Write(long value, Action<byte[]> before = null, Action<byte[]> after = null)
        {
            this.WriteInner(BufferUtility.ToBytes(value).Action(before)).Action(after);
        }

        public override void Write(ushort value, Action<byte[]> before = null, Action<byte[]> after = null)
        {
            this.WriteInner(BufferUtility.ToBytes(value).Action(before)).Action(after);
        }

        public override void Write(uint value, Action<byte[]> before = null, Action<byte[]> after = null)
        {
            this.WriteInner(BufferUtility.ToBytes(value).Action(before)).Action(after);
        }

        public override void Write(ulong value, Action<byte[]> before = null, Action<byte[]> after = null)
        {
            this.WriteInner(BufferUtility.ToBytes(value).Action(before)).Action(after);
        }

        public override void Write(string value, Action<byte[]> before = null, Action<byte[]> after = null)
        {
            this.Write(value, this.Encoding, before, after);
        }

        public override void Write(string value, Encoding encoding, Action<byte[]> before = null, Action<byte[]> after = null)
        {
            this.WriteInner(encoding.GetBytes(value).Action(before)).Action(after);
        }

    }


    public abstract class BufferWriter
    {

        public static BufferWriter Default
        {
            get { return new BigEndianBufferWriter(Encoding.Default); }
        }


        protected BufferWriter()
            : this(new MemoryStream(), Encoding.UTF8)
        {
        }

        protected BufferWriter(Encoding encoding)
            : this(new MemoryStream(), Encoding.UTF8)
        {
        }

        protected BufferWriter(Stream stream)
            : this(stream, Encoding.UTF8)
        {
        }

        protected BufferWriter(Stream stream, Encoding encoding)
        {
            this.BaseStream = stream;
            this.Encoding = encoding;
        }

        public Stream BaseStream
        {
            get;
            private set;
        }

        public Encoding Encoding
        {
            get;
            private set;
        }

        public long Length
        {
            get { return this.BaseStream.Length; }
        }

        public byte[] GetBuffer()
        {
            this.BaseStream.Flush();
            var result = new byte[this.BaseStream.Length];

            this.BaseStream.Seek(0, SeekOrigin.Begin);
            this.BaseStream.Read(result, 0, result.Length);
            return result;

            //var result = this.BaseStream as MemoryStream;
            // if (result != null)
            //    return result.GetBuffer();
            //return null;
        }

        public virtual long Seek(long offset)
        {
            return this.BaseStream.Seek(offset, SeekOrigin.Begin);
        }

        public abstract void Write(byte value, Action<byte[]> before = null, Action<byte[]> after = null);

        public abstract void Write(byte[] value, Action<byte[]> before = null, Action<byte[]> after = null);

        public abstract void Write(short value, Action<byte[]> before = null, Action<byte[]> after = null);

        public abstract void Write(int value, Action<byte[]> before = null, Action<byte[]> after = null);

        public abstract void Write(long value, Action<byte[]> before = null, Action<byte[]> after = null);

        public abstract void Write(ushort value, Action<byte[]> before = null, Action<byte[]> after = null);

        public abstract void Write(uint value, Action<byte[]> before = null, Action<byte[]> after = null);

        public abstract void Write(ulong value, Action<byte[]> before = null, Action<byte[]> after = null);

        public abstract void Write(string value, Action<byte[]> before = null, Action<byte[]> after = null);

        public abstract void Write(string value, Encoding encoding, Action<byte[]> before = null, Action<byte[]> after = null);
    }
}
